﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Threading;

namespace TanmiaGrp.Basis.Core
{
    public class BusinessObjectCollection<T> : ObservableCollection<T>
        where T : BusinessObject
    {
        protected List<BusinessObject> Added { get; set; }
        protected List<BusinessObject> Removed { get; set; }
        protected List<BusinessObject> Modified { get; set; }

        public BusinessObjectCollection()
        {
            Added = new List<BusinessObject>();
            Removed = new List<BusinessObject>();
            Modified = new List<BusinessObject>();
        }

        protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
        {
            if (e.Action == NotifyCollectionChangedAction.Add)
            {
                foreach (BusinessObject bizObj in e.NewItems)
                {
                    bizObj.PropertyChanged += OnBusinessObjectPropertyChanged;
                    Added.Add(bizObj);
                }
            }
            else if (e.Action == NotifyCollectionChangedAction.Remove)
            {
                foreach (BusinessObject bizObj in e.OldItems)
                {
                    bizObj.PropertyChanged -= OnBusinessObjectPropertyChanged;

                    // in case the deleted bizObj is added by hand, not from database.
                    if (Added.Contains(bizObj))
                        Added.Remove(bizObj);
                    else
                    {
                        // if deleted object was modifed before got deleting
                        if (Modified.Contains(bizObj))
                            Modified.Remove(bizObj);

                        Removed.Add(bizObj);
                    }
                }
            }

            //base.OnCollectionChanged(e);


            NotifyCollectionChangedEventHandler CollectionChanged = this.CollectionChanged;
            if (CollectionChanged != null)
                foreach (NotifyCollectionChangedEventHandler nh in CollectionChanged.GetInvocationList())
                {
                    DispatcherObject dispObj = nh.Target as DispatcherObject;
                    if (dispObj != null)
                    {
                        Dispatcher dispatcher = dispObj.Dispatcher;
                        if (dispatcher != null && !dispatcher.CheckAccess())
                        {
                            dispatcher.BeginInvoke(
                                (Action)(() => nh.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset))),
                                DispatcherPriority.DataBind);
                            continue;
                        }
                    }
                    nh.Invoke(this, e);
                }
        }

        public override event NotifyCollectionChangedEventHandler CollectionChanged;

        private void OnBusinessObjectPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            BusinessObject bizObj = sender as BusinessObject;
            if (!Added.Contains(bizObj))
            {
                Modified.Add(bizObj);
            }
        }

        public void ClearTracking()
        {
            Added.Clear();
            Removed.Clear();
            Modified.Clear();
        }
    }
}
